using System;

namespace Framework.Library.Core.Utils.Miscellaneous
{
    /// <summary>
    /// </summary>
    public static class EventUtils
    {
        public static void Raise<TDelegate>(TDelegate del, Action<TDelegate> raise) where TDelegate : class
        {
            if (del != null)
                raise(del);
        }

        public static void Raise<TEventArgs>(EventHandler<TEventArgs> del, object sender, TEventArgs args)
            where TEventArgs : EventArgs
        {
            if (del != null)
                del(sender, args);
        }

        public static TReturn Raise<TDelegate, TReturn>(TDelegate del, Func<TDelegate, TReturn> raise)
            where TDelegate : class
        {
            if (del != null)
                return raise(del);
            else
                return default(TReturn);
        }

        public static void RaiseAsync<TDelegate>(TDelegate del, Action<TDelegate> raise) where TDelegate : class
        {
            RaiseAsync(del, raise, null);
        }

        public static void RaiseAsync<TDelegate>(TDelegate del, Action<TDelegate> raise, EventCallBack callback)
            where TDelegate : class
        {
            RaiseAsync(del, delegate(TDelegate d)
                                {
                                    // call Action inside dummy Action<T>
                                    raise(d);
                                    return null;
                                },
                       delegate(EventResult<object> result)
                           {
                               // call EventCallBack inside dummy EventCallBack<T>
                               if (callback != null)
                                   callback(result);
                           });
        }

        public static void RaiseAsync<TDelegate, TReturn>(TDelegate del, Func<TDelegate, TReturn> raise)
            where TDelegate : class
        {
            RaiseAsync(del, raise, null);
        }

        public static void RaiseAsync<TDelegate, TReturn>(TDelegate del, Func<TDelegate, TReturn> raise,
                                                          EventCallBack<TReturn> callback) where TDelegate : class
        {
            if (del != null)
            {
                raise.BeginInvoke(del, delegate(IAsyncResult r)
                                           {
                                               Exception eventException = null;
                                               TReturn returnValue = default(TReturn);

                                               try
                                               {
                                                   // if an exception was thrown in the delegate, it will get raised here
                                                   returnValue = raise.EndInvoke(r);
                                               }
                                               catch (Exception e)
                                               {
                                                   eventException = e;
                                               }

                                               if (callback != null)
                                                   callback(new EventResult<TReturn>(returnValue, eventException));
                                           }, null);
            }
        }
    }
}